import time

import allure
from selenium import webdriver
from loguru import logger
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait


def exception_handle(fun):
    def magic(*args, **kwargs):
        _self: basePageHandler = args[0]
        try:
            result = fun(*args, **kwargs)
            # 清空错误次数
            _self._error_count = 0
            return result
        except Exception as e:
            # 如果次数太多，就退出异常逻辑，直接报错
            if _self._error_count > _self._error_max:
                raise e
            # 记录一直异常的次数
            _self._error_count += 1
            # 对黑名单里的弹框进行处理
            for element in _self._black_list:
                logger.info(element)
                elements = _self.driver.find_elements(*element)
                if len(elements) > 0:
                    elements[0].click()
                    # 继续寻找原来的正常控件
                    return magic(*args, **kwargs)
            # 如果黑名单也没有，就报错
            logger.warning("black list no one found")
            raise e

    return magic


class basePageHandler:
    """页面常用的操作"""
    # max = 0
    # black_list = [{"method": "", "value": ""}]

    _black_list = [
        # (By.ID, 'tv_agree'),
        # (By.XPATH, '//*[@text="确定"]'),
        # (By.ID, 'image_cancel'),
        # (By.XPATH, '//*[@text="下次再说"]')
    ]
    _error_max = 2
    _error_count = 0

    def __init__(self, driver: webdriver):
        self.driver = driver

    def find_element(self, locator: dict, value=True):
        """定位单个元素的方法"""
        return self.location_element("element", locator, value)

    def find_elements(self, locator: dict, value=None):
        """定位多个元素的方法"""
        return self.location_element("elements", locator, value=False)

    def location_element(self, findWay, locator: dict, value=True):
        """定位元素，可以对元素失败后，重复查找，次数可以设置，4代表最多查找5次，默认没有开启"""
        if "'" in locator["value"]:
            value = locator["value"].replace("'", "\"")
            locator["value"] = value
            # if value == True:
            # if isinstance(locator, dict):
            #     try:
            #         if findWay == "element":
            #             return self.location_method(locator["method"], locator["value"])
            #         else:
            #             return self.location_method(locator["method"], locator["value"], ele=False)
            #     except Exception as e:
            #         if self.max > 1:
            #             raise e
            #         self.max += 1
            #         for blak in self.black_list:
            #             if findWay == "element":
            #                 if not blak["method"] == "" and not blak["value"] == "":
            #                     elements = self.location_method(blak["method"], blak["value"])
            #                     if elements:
            #                         elements.click()
            #                 else:
            #                     continue
            #         logger.info("第" + str(self.max) + "次查找元素")
            # #         return self.location_element(findWay, locator)
            # else:
            #     raise RuntimeError(f"locator not is dict", locator)
            # else:
        if findWay == "element":
            return self.location_method(locator["method"], locator["value"])
        else:
            return self.location_method(locator["method"], locator["value"], ele=False)

    @exception_handle
    def location_method(self, name, locator, ele=True):
        """根据定位方法，查找元素"""
        if name == "xpath":
            if ele:
                element = f"self.driver.find_element_by_xpath('{locator}')"
            else:
                element = f"self.driver.find_elements_by_xpath('{locator}')"
        elif name == "css":
            if ele:
                element = f"self.driver.find_element_by_css_selector('{locator}')"
            else:
                element = f"self.driver.find_elements_by_css_selector('{locator}')"
        elif name == "id":
            if ele:
                element = f"self.driver.find_element_by_id('{locator}')"
            else:
                element = f"self.driver.find_elements_by_id('{locator}')"
        elif name == "name":
            if ele:
                element = f"self.driver.find_element_by_name('{locator}')"
            else:
                element = f"self.driver.find_elements_by_name('{locator}')"
        elif name == "classname":
            if ele:
                element = f"self.driver.find_element_by_class_name('{locator}')"
            else:
                element = f"self.driver.find_elements_by_class_name('{locator}')"
        elif name == "tagname":
            if ele:
                element = f"self.driver.find_element_by_tag_name('{locator}')"
        else:
            logger.info(f"not find location method：{(name, locator)}")
        return eval(element)

    def click_element(self, locator: dict, message="", step=""):
        """点击元素"""
        with allure.step(message):
            time.sleep(1)
            self.find_element(locator).click()
            logger.info(f"{step}  {locator}")
            return self

    def get_text(self, locator: dict, step=""):
        """获取text"""
        time.sleep(1)
        self.until_enable(locator, method=locator["method"])
        logger.info(f"{step}  {locator}")
        return self.find_element(locator).text

    def until_enable(self, locator, method, timeout=20, interval=1, ):
        if method == "css":
            WebDriverWait(self.driver, timeout, interval).until(
                expected_conditions.visibility_of_element_located((By.CSS_SELECTOR, locator["value"])))
        else:
            WebDriverWait(self.driver, timeout, interval).until(
                expected_conditions.visibility_of_element_located((By.XPATH, locator["value"])))

    def page_refresh(self):
        self.driver.refresh()

    def send_key(self, locator: dict, value, message="", step=""):
        """文本框输入"""
        with allure.step(message):
            if locator["method"] == "css":
                self.until_enable(locator, method="css")
            else:
                self.until_enable(locator, method="xpath")
            self.clear_element(locator)
            self.find_element(locator).send_keys(value)
            logger.info(f"{step}  {locator}  send_value: {value}")
        return self

    def quit(self):
        """退出浏览器进程"""
        self.driver.quit()
        return self

    def get_alter(self):
        time.sleep(1)
        return self.get_text({"method": "css", "value": "div.ant-message"})

    def get(self, url):
        """获取URL"""
        self.driver.get(url)
        return self

    def close(self):
        """关闭窗口"""
        self.driver.close()
        return self

    def clear_element(self, locator):
        """清除输入框"""
        self.find_element(locator).clear()
        return self

    def switch_windows(self):
        """窗口切换到最新打开的窗口"""
        # 获取打开的多个窗口句柄
        windows = self.driver.window_handles
        # 切换到当前最新打开的窗口
        self.driver.switch_to.window(windows[-1])
        return self

    def switch_ori(self):
        """回到开始的窗口"""
        windows = self.driver.window_handles
        # 切换到开始的窗口
        self.driver.switch_to.window(windows[0])
        return self

    def click_by_js(self, locator, message="", step=""):
        """使用js点击"""
        with allure.step(message):
            if locator["method"] == "xpath":
                self.driver.execute_script("arguments[0].click();", self.find_element(locator))
            if locator["method"] == "css":
                self.driver.execute_script("arguments[0].click();", self.find_element(locator))
            logger.info(f"{step}  {locator}")
        return self

    def wait_until_click_enable(self, locator: dict, times=20, interval=1, method="xpath"):
        if method == "xpath":
            WebDriverWait(self.driver, times, interval).until(
                expected_conditions.element_to_be_clickable((By.XPATH, locator["value"])))
        else:
            WebDriverWait(self.driver, times, interval).until(
                expected_conditions.element_to_be_clickable((By.CSS_SELECTOR, locator["value"])))

    def srollIntoView(self, locator):
        """滑动滚动到某个指定的元素"""
        self.driver.execute_script("arguments[0].scrollIntoView();", self.find_element(locator))
        return self

    def downSrollIntoView(self, pixel=300):
        """向下滚动300像素"""
        self.driver.execute_script(f"var q=document.getElementById('id').scrollTop={pixel}")
        return self

    def rightSrollIntoView(self, pixel=500):
        """向右滚动500像素"""
        self.driver.execute_script(f'window.scrollBy({pixel},0)')
        return self

    def down_right_srollIntoView(self, pixel=300, down=200):
        """向右滚动300像素，接着向下滚动200像素"""
        self.driver.execute_script(f'window.scrollBy({pixel},{down})')
        return self

    def upload_file_input(self, ):
        """input标签上传文件"""
        self.driver.sendKey(self.driver.find_element())
        return self

    def my_logs(self):
        ...
